package com.example.my_helper;

import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.net.DhcpInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.TextWatcher;
import android.text.style.ForegroundColorSpan;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.RequiresApi;

import com.example.my_helper.modbus4j.ModbusLocator;
import com.example.my_helper.modbus4j.code.DataType;


import java.io.IOException;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.TreeMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class ModbusDebuger {

    final static int ON_CONNECT = 0;
    final static int ON_MESSAGE = 1;
    final static int ON_SEND = 2;
    final static int ON_CLOSE = 3;
    final static int ON_ERROR = 4;
    final static int NOT_FOUND = 5;
    final static int NO_PERMISSION = 6;
    final static int CONFIG_ERROR = 7;
    final static int UNSUPPORT = 8;
    final static int CONSOLE_LOG = 9;
    final static int CONSOLE_REFRESH = 10;
    final static int SEND_DATA = 11;


    public MainActivity parent;
    public Handler handler;
    private WifiManager wifiManager;
    private WifiInfo wifiInfo;
    private DhcpInfo dhcpInfo;
    public MyModbusMaster myModbusMaster;

    View modbus_view;
    ListView register_list;
    ScrollView console_scroll;
    LinearLayout config_layout, serial_config_layout, host_config_layout;
    TextView console_text, recv_count_label, send_count_label, status_label;
    EditText host_add_input, host_port_input;
    Button open_bt, pause_bt, clear_bt, add_register_bt;
    ImageButton toggle_bt;
    Spinner modbus_mode_spinner, modbus_master_spinner, baudrate_spinner, databit_spinner;

    SpannableStringBuilder console_buf = new SpannableStringBuilder("");
    @SuppressLint("SimpleDateFormat")
    public SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    @SuppressLint("SimpleDateFormat")
    public SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("HH:mm:ss");


    final boolean[] flag = {false};
    int config_layout_heigth, config_hiden_layout_heigth;
    public boolean console_pause = false;
    public boolean auto_send_flag = false;
    public int recv_count = 0;
    public int send_count = 0;
    static boolean send_input_flag = false;
    public boolean console_lock = false;
    static int send_input_len = 0;
    private Lock lock = new ReentrantLock();
    private Lock rw_lock = new ReentrantLock();
    ArrayList<Register> registers;
    RegisterAdapter registerAdapter;

    @SuppressLint("ClickableViewAccessibility")
    public ModbusDebuger(MainActivity parent){
        this.parent = parent;
        this.modbus_view = parent.modbus_view;
        this.wifiManager = ((WifiManager) parent.getApplicationContext().getSystemService(Context.WIFI_SERVICE));
        this.myModbusMaster = new MyModbusMaster(this, handler);

        config_layout = modbus_view.findViewById(R.id.modbus_config_layout);
        serial_config_layout = modbus_view.findViewById(R.id.modbus_serial_config_layout);
        host_config_layout = modbus_view.findViewById(R.id.modbus_host_config_layout);
        console_scroll = modbus_view.findViewById(R.id.modbus_console_scroll);
        console_text = modbus_view.findViewById(R.id.modbus_console_text);
        recv_count_label = modbus_view.findViewById(R.id.modbus_recv_count_label);
        send_count_label = modbus_view.findViewById(R.id.modbus_send_count_label);
        status_label = modbus_view.findViewById(R.id.modbus_status_label);
        toggle_bt = modbus_view.findViewById(R.id.modbus_toggle_bt);
        open_bt = modbus_view.findViewById(R.id.modbus_open_bt);
        clear_bt = modbus_view.findViewById(R.id.modbus_clear_bt);
        pause_bt = modbus_view.findViewById(R.id.modbus_pause_bt);
        add_register_bt = modbus_view.findViewById(R.id.modbus_add_register_bt);
        modbus_mode_spinner = modbus_view.findViewById(R.id.modbus_mode_spinner);
        modbus_master_spinner = modbus_view.findViewById(R.id.modbus_master_spinner);
        host_add_input = modbus_view.findViewById(R.id.modbus_host_add_input);
        host_port_input = modbus_view.findViewById(R.id.modbus_host_port_input);
        baudrate_spinner = modbus_view.findViewById(R.id.modbus_baudrate_spinner);
        databit_spinner = modbus_view.findViewById(R.id.modbus_databit_spinner);
        register_list = modbus_view.findViewById(R.id.modbus_register_list);

        baudrate_spinner.setSelection(12);

        if (wifiManager.isWifiEnabled()) {
            host_add_input.setText(getGatework());
        }

        //registers.add(new Register("寄存器名称", "设备地址", "寄存器地址", "值", "更新时间"));
        registers = MyApp.myDBHelper.register_getdata();
        registerAdapter = new RegisterAdapter(registers, parent);
        register_list.setAdapter(registerAdapter);

        open_bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int id = modbus_mode_spinner.getSelectedItemPosition();
                if(open_bt.getText().equals("打开")) {
                    if (id < 2) {
                        if(MyApp.myUARTDriver.isOpen)
                        {
                            MyApp.myUARTDriver.Close();
                        }
                        int baudrate = Integer.parseInt(baudrate_spinner.getSelectedItem().toString());
                        MyApp.myUARTDriver.baudRate = baudrate;
                        MyApp.myUARTDriver.use_console_log = false;
                        MyApp.myUARTDriver.handler = handler;
                        myModbusMaster.handler = handler;
                        try {
                            if (MyApp.myUARTDriver.Open() == ON_CONNECT)
                                myModbusMaster.Init(id, baudrate);
                        }catch (Exception e){
                            Log_i(e.toString());
                        }
                    }else{
                        myModbusMaster.handler = handler;
                        String host = host_add_input.getText().toString();
                        int port = Integer.parseInt(host_port_input.getText().toString());
                        myModbusMaster.Init(id, host, port);
                    }
                }else{
                    //myModbusMaster.Unint();
                    if(id < 2)
                        MyApp.myUARTDriver.Close();
                    else
                        handler.sendEmptyMessage(ON_CLOSE);
                }
            }
        });

        clear_bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Console_clear();
            }
        });

        pause_bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(pause_bt.getText().equals("继续")) {
                    console_pause = false;
                    pause_bt.setText("暂停");
                    status_label.setText("状态：已连接");
                } else {
                    console_pause = true;
                    pause_bt.setText("继续");
                    status_label.setText("状态：已暂停");
                }
            }
        });

        toggle_bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(!flag[0]) {
                    toggle_bt.setBackground(parent.getDrawable(R.drawable.iov_arrow_up));
                    flag[0] = true;
                    config_layout_heigth = config_layout.getHeight();
                    hideConfigLayout();
                } else {
                    toggle_bt.setBackground(parent.getDrawable(R.drawable.iov_arrow_down));
                    flag[0] = false;
                    showConfigLayout();
                }
            }
        });

        modbus_mode_spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @SuppressLint("SetTextI18n")
            @Override
            public void onItemSelected(AdapterView<?> parent1, View view, int position, long id) {
                if(position > 1){
                    host_add_input.setEnabled(true);
                    host_port_input.setEnabled(true);
                    baudrate_spinner.setEnabled(false);
                    databit_spinner.setEnabled(false);
                }else{
                    host_add_input.setEnabled(false);
                    host_port_input.setEnabled(false);
                    baudrate_spinner.setEnabled(true);
                    databit_spinner.setEnabled(true);
                }
            }
            @Override
            public void onNothingSelected(AdapterView<?> parent) { }
        });

        add_register_bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                InitPopWindow(null, 0);
            }
        });

        register_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                InitPopWindow(registers.get(position), position);
            }
        });
        final float[] register_on_click_x = {0};
        register_list.setOnTouchListener(new View.OnTouchListener() {
            @SuppressLint("ClickableViewAccessibility")
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                register_on_click_x[0] = event.getX();
                return false;
            }
        });

        register_list.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent1, View view1, int position, long id) {
                Register reg = registers.get(position);

                View delete_view = LayoutInflater.from(parent).inflate(R.layout.register_control_layout, null, false);
                Button delete_bt = delete_view.findViewById(R.id.register_delete_bt);
                Button write_bt = delete_view.findViewById(R.id.register_write_bt);
                Button read_bt = delete_view.findViewById(R.id.register_read_bt);
                if(reg.register_class == 1 || reg.register_class == 3){
                    write_bt.setEnabled(false);
                }
                PopupWindow popWindow2 = new PopupWindow(delete_view,
                        ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
                popWindow2.setTouchable(true);
                popWindow2.setTouchInterceptor(new View.OnTouchListener() {
                    @Override
                    public boolean onTouch(View v, MotionEvent event) {
                        return false;
                    }
                });
                popWindow2.setBackgroundDrawable(new ColorDrawable(0x00000000));
                popWindow2.showAsDropDown(view1, (int)register_on_click_x[0]-200, 0);

                delete_bt.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        MyApp.myDBHelper.register_delete(registers.get(position).id1);
                        registers.remove(position);
                        registerAdapter.notifyDataSetChanged();
                        popWindow2.dismiss();
                    }
                });

                read_bt.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //读寄存器
                        if(myModbusMaster.inited){
                            new Thread(new Runnable() {
                                @SuppressLint("SetTextI18n")
                                @Override
                                public void run() {
                                    RegisterAdapter.ViewHolder viewHolder;
                                    Object obj;
                                    ModbusLocator locator;
                                    rw_lock.lock();
                                    try {
                                        Register r = registers.get(position);
                                        locator = new ModbusLocator(r.device_addr, r.register_class + 1, r.register_addr, getDataType(r.data_type, r.swapped));
                                        obj = myModbusMaster.master.getValue(locator);
                                        setDataValue(obj, r);
                                        viewHolder = (RegisterAdapter.ViewHolder) register_list.getChildAt(position).getTag();
                                        viewHolder.value.setText(r.value_str+r.unit);
                                        viewHolder.updata_time.setText(r.update_time);
                                    }catch (Exception e){
                                        e.printStackTrace();
                                        Log_error("读取失败，"+e.getMessage());
                                    }
                                    rw_lock.unlock();
                                }
                            }).start();

                        }else{
                            Toast.makeText(parent, "未连接", Toast.LENGTH_SHORT).show();
                        }
                        popWindow2.dismiss();
                    }
                });

                write_bt.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        popWindow2.dismiss();
                        //写寄存器
                        if(myModbusMaster.inited){
                            View write_view;
                            Spinner value_spinner = null;
                            EditText value_input = null;
                            if(reg.register_class == 0) {
                                write_view = LayoutInflater.from(parent).inflate(R.layout.register_write_window2, null, false);
                                value_spinner = write_view.findViewById(R.id.register_window_value_spinner);
                                if(reg.value_boolean != null)
                                    value_spinner.setSelection(reg.value_boolean?1:0);
                            }else{
                                write_view = LayoutInflater.from(parent).inflate(R.layout.register_write_window, null, false);
                                value_input = write_view.findViewById(R.id.register_window_value_inupt);
                                if(reg.value_str != null)
                                    value_input.setText(reg.value_str);
                            }
                            Button write1_bt = write_view.findViewById(R.id.register_window_write_bt);
                            Button cancel_bt = write_view.findViewById(R.id.register_window_cancel_bt);

                            PopupWindow popWindow3 = new PopupWindow(write_view,
                                    ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
                            popWindow3.setTouchable(true);
                            popWindow3.setTouchInterceptor(new View.OnTouchListener() {
                                @Override
                                public boolean onTouch(View v, MotionEvent event) {
                                    return false;
                                }
                            });
                            popWindow3.setOnDismissListener(new PopupWindow.OnDismissListener() {
                                @Override
                                public void onDismiss() {
                                    //popWindow.dismiss();
                                    WindowManager.LayoutParams lp = parent.getWindow().getAttributes();
                                    parent.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
                                    lp.alpha = 1f;
                                    parent.getWindow().setAttributes(lp);
                                }
                            });

                            popWindow3.setBackgroundDrawable(new ColorDrawable(0x00000000));
                            popWindow3.showAtLocation(modbus_view, Gravity.CENTER, 0, 0);
                            WindowManager.LayoutParams lp = parent.getWindow().getAttributes();
                            parent.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
                            lp.alpha = 0.3f;
                            parent.getWindow().setAttributes(lp);

                            Spinner finalValue_spinner1 = value_spinner;
                            EditText finalValue_input = value_input;
                            write1_bt.setOnClickListener(new View.OnClickListener() {
                                @RequiresApi(api = Build.VERSION_CODES.O)
                                @Override
                                public void onClick(View v) {
                                    Object object;
                                    try {
                                        if (reg.register_class == 0) {
                                            assert finalValue_spinner1 != null;
                                            object = finalValue_spinner1.getSelectedItemPosition() == 1;
                                        } else {
                                            assert finalValue_input != null;
                                            object = getDataValue(finalValue_input.getText().toString(), reg.data_type);
                                        }
                                    }catch (Exception e){
                                        e.printStackTrace();
                                        Toast.makeText(parent, "非法输入", Toast.LENGTH_SHORT).show();
                                        return;
                                    }

                                    new Thread(new Runnable() {
                                        @SuppressLint("SetTextI18n")
                                        @Override
                                        public void run() {
                                            RegisterAdapter.ViewHolder viewHolder;
                                            ModbusLocator locator;
                                            rw_lock.lock();
                                            try {
                                                locator = new ModbusLocator(reg.device_addr, reg.register_class + 1, reg.register_addr, getDataType(reg.data_type, reg.swapped));
                                                myModbusMaster.master.setValue(locator, object);
                                            }catch (Exception e){
                                                e.printStackTrace();
                                                Log_error("写入失败，"+e.getMessage());
                                            }
                                            rw_lock.unlock();
                                        }
                                    }).start();
                                    popWindow3.dismiss();
                                }
                            });

                            cancel_bt.setOnClickListener(new View.OnClickListener() {
                                @Override
                                public void onClick(View v) {
                                    //MyApp.myDBHelper.kuaijie_delete(adapter.getItem(position));
                                    popWindow3.dismiss();
                                }
                            });

                        }else{
                            Toast.makeText(parent, "未连接", Toast.LENGTH_SHORT).show();
                        }
                    }
                });
                return true;
            }
        });

        handler = new Handler(msg -> {
            String s;
            switch(msg.what){
                case ON_CONNECT:
                    open_bt.setText("关闭");
                    if(modbus_mode_spinner.getSelectedItemPosition() < 2) {
                        baudrate_spinner.setEnabled(false);
                        databit_spinner.setEnabled(false);
                    }else {
                        host_add_input.setEnabled(false);
                        host_port_input.setEnabled(false);
                    }
                    modbus_mode_spinner.setEnabled(false);
                    modbus_master_spinner.setEnabled(false);
                    status_label.setText("状态：已连接");
                    Log_i("已打开");
                    new ReadThread().start();
                    break;
                case ON_MESSAGE:
                    break;
                case ON_SEND:
                    break;
                case ON_CLOSE:
                    open_bt.setText("打开");
                    if(modbus_mode_spinner.getSelectedItemPosition() < 2) {
                        baudrate_spinner.setEnabled(true);
                        databit_spinner.setEnabled(true);
                    }else {
                        host_add_input.setEnabled(true);
                        host_port_input.setEnabled(true);
                    }
                    modbus_mode_spinner.setEnabled(true);
                    modbus_master_spinner.setEnabled(true);
                    status_label.setText("状态：未连接");
                    myModbusMaster.Unint();
                    Log_i("已关闭");
                    break;
                case ON_ERROR:
                    Log_i("连接失败");
                    break;
                case CONFIG_ERROR:
                    Log_i("串口配置错误");
                    break;
                case NOT_FOUND:
                    Log_i("未发现设备");
                    break;
                case NO_PERMISSION:
                    Log_i("未获取USB权限");
                    break;
                case UNSUPPORT:
                    Log_i("你的设备不支持USB主机模式");
                    break;
                case CONSOLE_LOG:
                    /*lock.lock();
                    console_text.setText(console_buf);
                    lock.unlock();*/
                    if(console_text.length() > 5000){
                        console_text.setText((CharSequence) msg.obj);
                    }else{
                        console_text.append((CharSequence) msg.obj);
                    }
                    if(console_lock)
                        break;
                    console_lock = true;
                    console_scroll.post(new Runnable() {
                        @Override
                        public void run() {
                            console_scroll.fullScroll(View.FOCUS_DOWN);
                            console_lock = false;
                        }
                    });
                    break;
                case CONSOLE_REFRESH:
                    console_text.setText("");
                    send_count = 0;
                    recv_count = 0;
                    send_count_label.setText("发送：0");
                    recv_count_label.setText("接收：0");
                    break;
                default:
                    break;
            }
            return false;
        });

    }

    @SuppressLint("SetTextI18n")
    private void InitPopWindow(Register r, int position) {
        EditText register_name, device_addr, register_addr, register_num, bit_offset, ratio, unit, period;
        View register_view = LayoutInflater.from(parent).inflate(R.layout.register_window, null, false);
        ListView listView = (ListView) register_view.findViewById(R.id.kuaijie_list);
        Button register_save_bt = register_view.findViewById(R.id.register_save_bt);
        Button register_cancel_bt = register_view.findViewById(R.id.register_cancel_bt);
        Spinner class_spinner = register_view.findViewById(R.id.register_class_spinner);
        Spinner data_type_spinner = register_view.findViewById(R.id.register_data_type_spinner);
        register_name = register_view.findViewById(R.id.register_name_input);
        device_addr = register_view.findViewById(R.id.device_addr_input);
        register_addr = register_view.findViewById(R.id.register_addr_input);
        Spinner swapped_spinner = register_view.findViewById(R.id.mudbus_swapped_spinner);
        CheckBox hex_show_check = register_view.findViewById(R.id.modbus_hex_show_check);
        TextView bit_num = register_view.findViewById(R.id.register_bit_width_label);
        ratio = register_view.findViewById(R.id.register_ratio_input);
        unit = register_view.findViewById(R.id.register_uint_input);
        period = register_view.findViewById(R.id.register_period_input);
        CheckBox auto_send_check = register_view.findViewById(R.id.modbus_auto_read_check);
        TextView register_window_title = register_view.findViewById(R.id.register_window_title);

        auto_send_check.setChecked(false);
        period.setEnabled(false);

        if(r != null){
            register_window_title.setText("修改寄存器");
            register_name.setText(r.register_name);
            register_addr.setText(r.register_addr_str);
            device_addr.setText(r.device_addr_str);
            class_spinner.setSelection(r.register_class);
            data_type_spinner.setSelection(r.data_type);
            swapped_spinner.setSelection(r.swapped?1:0);
            hex_show_check.setChecked(r.hex_show);
            ratio.setText(""+r.ratio);
            unit.setText(r.unit);
            if(r.period == 0){
                auto_send_check.setChecked(false);
                period.setEnabled(false);
            }else {
                auto_send_check.setChecked(true);
                period.setEnabled(true);
                period.setText("" + r.period);
            }
        }

        auto_send_check.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if(isChecked){
                    period.setEnabled(true);
                }else{
                    period.setEnabled(false);
                }
            }
        });

        class_spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent1, View view, int position, long id) {
                if(position > 1){
                    if(r == null)
                        data_type_spinner.setSelection(1);
                    data_type_spinner.setEnabled(true);
                    ratio.setEnabled(true);
                }else{
                    data_type_spinner.setSelection(0);
                    data_type_spinner.setEnabled(false);
                    bit_num.setText("1位");
                    ratio.setText("1");
                    ratio.setEnabled(false);
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });

        data_type_spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent1, View view, int position, long id) {
                if(position == 0){
                    bit_num.setText("1位");
                    ratio.setText("1");
                    ratio.setEnabled(false);
                }else if(position > 0 && position < 7){
                    int n;
                    if(position % 2 == 0){
                        n = (int) Math.pow(2, (position/2)+3);
                    }else{
                        n = (int) Math.pow(2, ((position+1)/2)+3);
                    }
                    bit_num.setText(n+"位");
                    ratio.setEnabled(true);
                }else{
                    if(position == 7){
                        bit_num.setText("32位");
                        ratio.setEnabled(true);
                    }else{
                        bit_num.setText("64位");
                        ratio.setEnabled(true);
                    }
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });



        //1.构造一个PopupWindow，参数依次是加载的View，宽高
        PopupWindow popWindow = new PopupWindow(register_view, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
        popWindow.setAnimationStyle(R.style.popupAnimation);  //设置加载动画
        popWindow.setTouchable(true);
        popWindow.setTouchInterceptor(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return false;
            }
        });
        popWindow.setBackgroundDrawable(new ColorDrawable(0x00000000));    //要为popWindow设置一个背景才有效
        popWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
            @Override
            public void onDismiss() {
                //popWindow.dismiss();
                WindowManager.LayoutParams lp = parent.getWindow().getAttributes();
                parent.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
                lp.alpha = 1f;
                parent.getWindow().setAttributes(lp);
            }
        });
        register_cancel_bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                popWindow.dismiss();
            }
        });

        register_save_bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(register_addr.length() == 0 || register_name.length() == 0 || device_addr.length() == 0){
                    Toast.makeText(parent, "输入不能为空", Toast.LENGTH_SHORT).show();
                    return;
                }
                rw_lock.lock();
                try {
                    if (r != null) {
                        r.register_name = register_name.getText().toString();
                        r.setDevice_addr(device_addr.getText().toString());
                        r.setRegister_addr(register_addr.getText().toString());
                        r.ratio = Float.parseFloat(ratio.getText().toString());
                        r.unit = unit.getText().toString();
                        if(!auto_send_check.isChecked()){
                            r.period = 0;
                        }else{
                            r.period = Integer.parseInt(period.getText().toString());
                            if(r.period > 0 && r.period < 10){
                                r.period = 10;
                                period.setText("10");
                                Toast.makeText(parent, "最小间隔为10ms", Toast.LENGTH_SHORT).show();
                            }
                        }
                        r.setRegister_type(class_spinner.getSelectedItemPosition());
                        r.data_type = data_type_spinner.getSelectedItemPosition();
                        r.swapped = swapped_spinner.getSelectedItemPosition() != 0;
                        r.hex_show = hex_show_check.isChecked();
                        registerAdapter.notifyDataSetChanged();
                        MyApp.myDBHelper.register_update(r);
                    } else {
                        Register register = new Register(register_name.getText().toString(), class_spinner.getSelectedItemPosition(), register_addr.getText().toString(), "", "");
                        register.setDevice_addr(device_addr.getText().toString());
                        register.setRegister_addr(register_addr.getText().toString());
                        register.ratio = Integer.parseInt(ratio.getText().toString());
                        register.unit = unit.getText().toString();
                        if(!auto_send_check.isChecked()){
                            register.period = 0;
                        }else{
                            register.period = Integer.parseInt(period.getText().toString());
                            if(register.period > 0 && register.period < 10){
                                register.period = 10;
                                period.setText("10");
                                Toast.makeText(parent, "最小间隔为10ms", Toast.LENGTH_SHORT).show();
                            }
                        }
                        register.data_type = data_type_spinner.getSelectedItemPosition();
                        register.swapped = swapped_spinner.getSelectedItemPosition() != 0;
                        register.hex_show = hex_show_check.isChecked();
                        register.id1 = System.currentTimeMillis();
                        registers.add(0, register);
                        registerAdapter.notifyDataSetChanged();
                        MyApp.myDBHelper.register_insert(register);
                    }
                    popWindow.dismiss();
                }catch(Exception e){
                    e.printStackTrace();
                    Toast.makeText(parent, "非法输入", Toast.LENGTH_SHORT).show();
                }
                rw_lock.unlock();
            }
        });
        //popWindow.showAsDropDown(serial_view, 50, 50);
        popWindow.showAtLocation(modbus_view, Gravity.CENTER, 0, 0);
        WindowManager.LayoutParams lp = parent.getWindow().getAttributes();
        parent.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
        lp.alpha = 0.3f;
        parent.getWindow().setAttributes(lp);
    }

    class ReadThread extends Thread{
        @SuppressLint("SetTextI18n")
        @Override
        public void run() {
            RegisterAdapter.ViewHolder viewHolder;
            Object obj;
            ModbusLocator locator;
            int position = 0;
            long time;
            while (myModbusMaster.inited){
                rw_lock.lock();
                position = 0;
                for(Register r : registers){
                    if(r.period != 0){
                        time = System.currentTimeMillis();
                        if(time - r.time_tick >= r.period){
                            try {
                                locator = new ModbusLocator(r.device_addr, r.register_class+1, r.register_addr, getDataType(r.data_type, r.swapped));
                                obj = myModbusMaster.master.getValue(locator);
                                setDataValue(obj, r);
                                viewHolder = (RegisterAdapter.ViewHolder) register_list.getChildAt(position).getTag();
                                viewHolder.value.setText(r.value_str+r.unit);
                                viewHolder.updata_time.setText(r.update_time);
                            } catch (Exception e) {
                                e.printStackTrace();
                                Log_error("读取失败，"+e.getMessage());
                            }
                            r.time_tick = System.currentTimeMillis();
                        }else if(time < r.time_tick){
                            r.time_tick = time;
                        }
                    }
                    position++;
                }
                rw_lock.unlock();

                try {
                    Thread.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Log.i("===1111", "readThread closed");
        }
    }

    public int getDataType(int data_type, boolean swapped){
        int dataType = DataType.BINARY;
        switch(data_type){
            case 0:
                dataType = DataType.BINARY;
                break;
            case 1:
                dataType = DataType.TWO_BYTE_INT_SIGNED;
                break;
            case 2:
                dataType = DataType.TWO_BYTE_INT_UNSIGNED;
                break;
            case 3:
                if(!swapped){
                    dataType = DataType.FOUR_BYTE_INT_SIGNED;
                }else{
                    dataType = DataType.FOUR_BYTE_INT_SIGNED_SWAPPED;
                }
                break;
            case 4:
                if(!swapped){
                    dataType = DataType.FOUR_BYTE_INT_UNSIGNED;
                }else{
                    dataType = DataType.FOUR_BYTE_INT_UNSIGNED_SWAPPED;
                }
                break;
            case 5:
                if(!swapped){
                    dataType = DataType.EIGHT_BYTE_INT_SIGNED;
                }else{
                    dataType = DataType.EIGHT_BYTE_INT_SIGNED_SWAPPED;
                }
                break;
            case 6:
                if(!swapped){
                    dataType = DataType.EIGHT_BYTE_INT_UNSIGNED;
                }else{
                    dataType = DataType.EIGHT_BYTE_INT_UNSIGNED_SWAPPED;
                }
                break;
            case 7:
                if(!swapped){
                    dataType = DataType.FOUR_BYTE_FLOAT;
                }else{
                    dataType = DataType.FOUR_BYTE_FLOAT_SWAPPED;
                }
                break;
            case 8:
                if(!swapped){
                    dataType = DataType.EIGHT_BYTE_FLOAT;
                }else{
                    dataType = DataType.EIGHT_BYTE_FLOAT_SWAPPED;
                }
                break;
        }
        return dataType;
    }

    public void setDataValue(Object object, Register r){
        int dataType = DataType.BINARY;
        switch(r.data_type){
            case 0:
                r.value_boolean = (Boolean) object;
                r.value_str = r.value_boolean.toString();
                break;
            case 1:
                r.value_short = (Short) object;
                if(!r.hex_show){
                    r.value_str = Short.valueOf((short) (r.ratio*r.value_short)).toString();
                }else{
                    r.value_str = "0x"+Integer.toHexString(r.value_short);
                }
                break;
            case 2:
                r.value_ushort = (Integer) object;
                if(!r.hex_show){
                    r.value_str = Integer.valueOf((int) (r.ratio*r.value_ushort)).toString();
                }else{
                    r.value_str = "0x"+Integer.toHexString(r.value_ushort);
                }
                break;
            case 3:
                r.value_int = (Integer) object;
                if(!r.hex_show){
                    r.value_str = Integer.valueOf((int) (r.ratio*r.value_int)).toString();
                }else{
                    r.value_str = "0x"+Integer.toHexString(r.value_int);
                }
                break;
            case 4:
                r.value_uint = (Long) object;
                if(!r.hex_show){
                    r.value_str = Long.valueOf((long) (r.ratio*r.value_uint)).toString();
                }else{
                    r.value_str = "0x"+Long.toHexString(r.value_uint);
                }
                break;
            case 5:
                r.value_long = (Long) object;
                if(!r.hex_show){
                    r.value_str = Long.valueOf((long) (r.ratio*r.value_long)).toString();
                }else{
                    r.value_str = "0x"+Long.toHexString(r.value_long);
                }
                break;
            case 6:
                r.value_ulong = (BigInteger) object;
                if(!r.hex_show){
                    r.value_str = BigInteger.valueOf((long) (r.ratio*r.value_ulong.longValue())).toString();
                }else{
                    r.value_str = "0x"+r.value_ulong.toString(16);
                }
                break;
            case 7:
                r.value_float = (Float) object;
                if(!r.hex_show){
                    r.value_str = Float.valueOf(r.ratio*r.value_float).toString();
                }else{
                    r.value_str = "0x"+Integer.toHexString((Integer) object);
                }
                break;
            case 8:
                r.value_double = (Double) object;
                if(!r.hex_show){
                    r.value_str = Double.valueOf(r.ratio*r.value_double).toString();
                }else{
                    r.value_str = "0x"+Double.toHexString(r.value_double);
                }
                break;
        }
        r.update_time = simpleDateFormat2.format(new Date(System.currentTimeMillis()));
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    public Object getDataValue(String s, int data_type){
        Object object;
        boolean flag = false;
        s = s.toLowerCase();
        if(s.startsWith("0x")){
            s = s.substring(2);
            flag = true;
        }
        switch(data_type){
            case 0:
            case 1:
            case 2:
            case 3:
                if(!flag)
                    object = Integer.parseInt(s);
                else
                    object = Integer.parseUnsignedInt(s, 16);
                break;
            case 4:
            case 5:
                if(!flag)
                    object = Long.parseLong(s);
                else
                    object = Long.parseLong(s, 16);
                break;
            case 6:
                if(!flag)
                    object = Long.parseUnsignedLong(s);
                else
                    object = Long.parseUnsignedLong(s, 16);
                break;
            case 7:
                object = Float.parseFloat(s);
                break;
            case 8:
                object = Double.parseDouble(s);
                break;
            default:
                throw new IllegalStateException("Unexpected value: " + data_type);
        }
        return object;
    }

    public void Log_i(String s){
        if(console_pause)
            return;
        lock.lock();
        /*if(console_buf.length() > 1000){
            console_buf = new SpannableStringBuilder();
        }
        int start = console_buf.length();*/
        console_buf = new SpannableStringBuilder();
        console_buf.append("[").append(simpleDateFormat.format(new Date(System.currentTimeMillis()))).append("]:");
        console_buf.append(s).append("\n");
        ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.BLACK);
        console_buf.setSpan(foregroundColorSpan, 0, console_buf.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
        lock.unlock();
        Message msg = new Message();
        msg.obj = console_buf;
        msg.what = CONSOLE_LOG;
        handler.sendMessage(msg);
    }

    public void Log_error(String s){
        if(console_pause)
            return;
        lock.lock();
        /*if(console_buf.length() > 1000){
            console_buf = new SpannableStringBuilder();
        }
        int start = console_buf.length();*/
        console_buf = new SpannableStringBuilder();
        console_buf.append("[").append(simpleDateFormat.format(new Date(System.currentTimeMillis()))).append("]:");
        console_buf.append(s).append("\n");
        ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.RED);
        console_buf.setSpan(foregroundColorSpan, 0, console_buf.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
        lock.unlock();
        Message msg = new Message();
        msg.obj = console_buf;
        msg.what = CONSOLE_LOG;
        handler.sendMessage(msg);
    }

    @SuppressLint("SetTextI18n")
    public synchronized void Log_msg(int msg_type, byte[] buf, int len) {
        if(msg_type == 0) {
            recv_count += len;
            recv_count_label.setText("接收：" + recv_count);
        }else{
            send_count += len;
            send_count_label.setText("发送：" + send_count);
        }
        if(console_pause)
            return;

        lock.lock();
       /*if(console_buf.length() > 1000){
            console_buf = new SpannableStringBuilder();
        }
        int start = console_buf.length();*/
        console_buf = new SpannableStringBuilder();
        if(msg_type == 0){
            console_buf.append("[").append(simpleDateFormat.format(new Date(System.currentTimeMillis()))).append("]<<<:");
        }else{
            console_buf.append("[").append(simpleDateFormat.format(new Date(System.currentTimeMillis()))).append("]>>>:");
        }
        StringBuilder s = new StringBuilder();
        String ss;
        for(int i = 0; i < len; i++){
            ss = Integer.toHexString(buf[i]&0xff);
            if(ss.length() == 1)
                ss = "0"+ss;
            s.append(ss).append(" ");
        }
        console_buf.append(s.toString()).append("\n");
        ForegroundColorSpan foregroundColorSpan;
        if(msg_type == 0){
            foregroundColorSpan = new ForegroundColorSpan(Color.GREEN);
        }else{
            foregroundColorSpan = new ForegroundColorSpan(Color.BLUE);
        }
        console_buf.setSpan(foregroundColorSpan, 0, console_buf.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
        lock.unlock();
        Message msg = new Message();
        msg.obj = console_buf;
        msg.what = CONSOLE_LOG;
        handler.sendMessage(msg);
    }

    public void Console_clear()
    {
        /*lock.lock();
        console_buf = new SpannableStringBuilder();
        lock.unlock();*/
        handler.sendEmptyMessage(CONSOLE_REFRESH);
    }

    private void showConfigLayout(){
        TypeEvaluator<ViewGroup.LayoutParams> evaluator = new HeightEvaluator();
        ViewGroup.LayoutParams start = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0);
        ViewGroup.LayoutParams end = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, config_layout_heigth);
        ValueAnimator animator = ObjectAnimator.ofObject(config_layout, "layoutParams", evaluator, start, end);
        AnimatorSet set = new AnimatorSet();
        set.play(animator);
        set.setDuration(500);
        set.start();
    }
    private void hideConfigLayout() {
        TypeEvaluator<ViewGroup.LayoutParams> evaluator = new HeightEvaluator();
        ViewGroup.LayoutParams start = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, config_layout_heigth);
        ViewGroup.LayoutParams end = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0);
        ValueAnimator animator = ObjectAnimator.ofObject(config_layout, "layoutParams", evaluator, start, end);
        AnimatorSet set = new AnimatorSet();
        set.play(animator);
        set.setDuration(500);
        set.start();
    }
    class HeightEvaluator implements TypeEvaluator<ViewGroup.LayoutParams> {
        @Override
        public ViewGroup.LayoutParams evaluate(float fraction, ViewGroup.LayoutParams startValue, ViewGroup.LayoutParams endValue) {
            ViewGroup.LayoutParams params = config_layout.getLayoutParams();
            params.height = (int) (startValue.height + fraction * (endValue.height - startValue.height));
            return params;
        }
    }

    private String intToIp(int i) {

        return (i & 0xFF ) + "." +
                ((i >> 8 ) & 0xFF) + "." +
                ((i >> 16 ) & 0xFF) + "." +
                ( i >> 24 & 0xFF) ;
    }
    /**
     * 获取当前ip地址
     */
    public String getLocalHost() {
        wifiInfo = wifiManager.getConnectionInfo();
        return intToIp(wifiInfo.getIpAddress());
    }

    public String getGatework() {
        dhcpInfo = wifiManager.getDhcpInfo();
        return intToIp(dhcpInfo.gateway);
    }

}
